home *** CD-ROM | disk | FTP | other *** search
- {*****************************************************************************}
- { }
- { TAppBar Class v1.1 }
- { implements Application Desktop Toolbar }
- { (based on J.Richter's CAppBar MFC Class) }
- { }
- { Copyright (c) 1997 Paolo Giacomuzzi }
- { e-mail: paolo.giacomuzzi@usa.net }
- { http://www.geocities.com/SiliconValley/9486 }
- { }
- {*****************************************************************************}
-
- unit AppBar;
-
-
- interface
-
-
- uses
- Windows, Messages, SysUtils, Classes, Forms, Dialogs, Controls, ExtCtrls,
- ShellApi;
-
-
- const
- // AppBar's user notification message
- WM_APPBARNOTIFY = WM_USER + 100;
-
- // Timer interval
- AUTO_HIDE_TIMER_INTERVAL = 400; // milliseconds
-
- // Defaults
- AB_DEF_SIZE_INC = 1;
- AB_DEF_DOCK_DIM = 32;
-
-
- type
- // You can send to the Windows shell one of the following messages:
- // Message Description
- // -------------- --------------------------------------------------
- // ABM_NEW Register a new AppBar to the system
- // ABM_REMOVE Remove a previously created AppBar from the system
- // ABM_QUERYPOS Query the AppBar position
- // ABM_SETPOS Set the AppBar position
- // ABM_GETSTATE Get the edge the Appbar is docked to
- // ABM_GETTASKBARPOS Get the Explorer Taskbar position
- // ABM_ACTIVATE Activate the AppBar
- // ABM_GETAUTOHIDEBAR Query if AppBar has Auto-hide behavior
- // ABM_SETAUTOHIDEBAR Set the AppBar's Auto-hide behavior
-
- // The ABM_message constants are defined in SHELLAPI.PAS as follows:
- // ABM_NEW = $00000000;
- // ABM_REMOVE = $00000001;
- // ABM_QUERYPOS = $00000002;
- // ABM_SETPOS = $00000003;
- // ABM_GETSTATE = $00000004;
- // ABM_GETTASKBARPOS = $00000005;
- // ABM_ACTIVATE = $00000006;
- // ABM_GETAUTOHIDEBAR = $00000007;
- // ABM_SETAUTOHIDEBAR = $00000008;
- // ABM_WINDOWPOSCHANGED = $00000009;
-
- // The following enumerated type defines the constants in the table
- TAppBarMessage = (abmNew, abmRemove, abmQueryPos, abmSetPos, abmGetState,
- abmGetTaskBarPos, abmActivate, abmGetAutoHideBar,
- abmSetAutoHideBar, abmWindowPosChanged);
-
- // An AppBar can be in one of 6 states shown in the table below:
- // State Description
- // ----------- -----------------------------------------------------
- // ABE_UNKNOWN The Appbar is in an unknown state
- // (usually during construction/destruction)
- // ABE_FLOAT The AppBar is floating on the screen
- // ABE_LEFT The Appbar is docked on the left edge of the screen
- // ABE_TOP The Appbar is docked on the top edge of the screen
- // ABE_RIGHT The Appbar is docked on the right edge of the screen
- // ABE_BOTTOM The Appbar is docked on the bottom edge of the screen
-
- // The ABE_edge state constants are defined in SHELLAPI.PAS as follows:
- // ABE_LEFT = 0;
- // ABE_TOP = 1;
- // ABE_RIGHT = 2;
- // ABE_BOTTOM = 3;
-
- // The ABE_UNKNOWN and ABE_FLOAT constants are defined here as follows:
- // ABE_UNKNOWN = 4;
- // ABE_FLOAT = 5;
-
- // The following enumerated type defines the constants in the table
- // (Values are mutually exclusive)
- TAppBarEdge = (abeLeft, abeTop, abeRight, abeBottom, abeUnknown, abeFloat);
-
- // An AppBar can have several behavior flags as shown below:
- // Flag Description
- // --------------------------- -----------------------------------
- // ABF_ALLOWLEFT Allow dock on left of screen
- // ABF_ALLOWRIGHT Allow dock on right of screen
- // ABF_ALLOWTOP Allow dock on top of screen
- // ABF_ALLOWBOTTOM Allow dock on bottom of screen
- // ABF_ALLOWFLOAT Allow float in the middle of screen
-
- // The following enumerated type defines the constants in the table
- TAppBarFlag = (abfAllowLeft, abfAllowTop, abfAllowRight, abfAllowBottom,
- abfAllowFloat);
- TAppBarFlags = set of TAppBarFlag;
-
- // The record below contains all of the AppBar settings that
- // can be saved/loaded in/from the Registry
- TAppBarSettings = record
- cbSize : DWORD; // Size of this structure
- abEdge : TAppBarEdge; // ABE_UNKNOWN, ABE_FLOAT, or ABE_edge
- bAutohide : Boolean; // Should AppBar be auto-hidden when docked?
- bAlwaysOnTop : Boolean; // Should AppBar always be on top?
- rcDockDims : TRect; // Width/height for docked bar on 4 edges
- rcFloat : TRect; // Floating rectangle (in screen coordinates)
- nMinWidth : LongInt; // Min allowed width
- nMinHeight : LongInt; // Min allowed height
- nMaxWidth : LongInt; // Max allowed width
- nMaxHeight : LongInt; // Max allowed height
- end;
-
- // TAppBar class ////////////////////////////////////////////////////////////
- TAppBar = class(TForm)
-
- private
-
- { Internal implementation state variables }
-
- // This AppBar's settings info
- FABS : TAppBarSettings;
-
- // ABF_* flags
- FabFlags : TAppBarFlags;
-
- // Discrete width/height size increments
- FszSizeInc : TSize;
-
- // We need a member variable which tracks the proposed edge of the
- // AppBar while the user is moving it, deciding where to position it.
- // While not moving, this member must contain ABE_UNKNOWN so that
- // GetEdge returns the current edge contained in FABS.abEdge.
- // While moving the AppBar, FabEdgeProposedPrev contains the
- // proposed edge based on the position of the AppBar. The proposed
- // edge becomes the new edge when the user stops moving the AppBar.
- FabEdgeProposedPrev : TAppBarEdge;
-
- // We need a member variable which tracks whether a full screen
- // application window is open
- FbFullScreenAppOpen : Boolean;
-
- // We need a member variable which tracks whether our autohide window
- // is visible or not
- FbAutoHideIsVisible : Boolean;
-
- // We need a timer to to determine when the AppBar should be re-hidden
- FTimer : TTimer;
-
- { Internal implementation functions }
-
- // Modifies window creation flags
- procedure CreateParams (var Params: TCreateParams); override;
-
- // These functions encapsulate the shell's SHAppBarMessage function
- function AppBarMessage (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge;
- lParam : LPARAM;
- bRect : Boolean;
- var rc : TRect) : UINT;
-
- function AppBarMessage1 (abMessage : TAppBarMessage) : UINT;
-
- function AppBarMessage2 (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge) : UINT;
-
- function AppBarMessage3 (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge;
- lParam : LPARAM) : UINT;
-
- function AppBarMessage4 (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge;
- lParam : LPARAM;
- var rc : TRect) : UINT;
-
- // Gets a edge (ABE_FLOAT or ABE_edge) from a point (screen coordinates)
- function CalcProposedState (var pt : TSmallPoint) : TAppBarEdge;
-
- // Gets a retangle position (screen coordinates) from a proposed state
- procedure GetRect (abEdgeProposed : TAppBarEdge; var rcProposed : TRect);
-
- // Adjusts the AppBar's location to account for autohide
- // Returns TRUE if rectangle was adjusted
- function AdjustLocationForAutohide (bShow : Boolean;
- var rc : TRect) : Boolean;
-
- // If AppBar is Autohide and docked, shows/hides the AppBar
- procedure ShowHiddenAppBar (bShow : Boolean);
-
- // When Autohide AppBar is shown/hidden, slides in/out of view
- procedure SlideWindow (var rcEnd : TRect);
-
- // Returns which edge we're autohidden on or ABE_UNKNOWN
- function GetAutohideEdge : TAppBarEdge;
-
- // Returns a TSmallPoint that gives the cursor position in screen coords
- function GetMessagePosition : TSmallPoint;
-
- // Changes the style of a window (translated from AfxModifyStyle)
- function ModifyStyle (hWnd : THandle;
- nStyleOffset : Integer;
- dwRemove : DWORD;
- dwAdd : DWORD;
- nFlags : UINT) : Boolean;
-
- protected
-
- { Property selector functions }
-
- // Retrieves the AppBar's edge. If the AppBar is being positioned, its
- // proposed state is returned instead
- function GetEdge : TAppBarEdge;
-
- // Changes the AppBar's edge to ABE_UNKNOWN, ABE_FLOAT or an ABE_edge
- procedure SetEdge (abEdge : TAppBarEdge);
-
- // Returns TRUE if Auto-hide is on, FALSE if Auto-hide is off
- function IsAutoHide : Boolean;
-
- // Sets the Auto-hide behavior
- procedure SetAutoHide (bAutoHide : Boolean);
-
- // Returns TRUE if AppBar is always on topAuto-hide, FALSE otherwise
- function IsAlwaysOnTop : Boolean;
-
- // Sets the AlwaysOnTop behavior
- procedure SetAlwaysOnTop (bAlwaysOnTop : Boolean);
-
- // Gets the AppBar's floating rectangle
- function GetFloatRect : TRect;
-
- // Sets the AppBar's floating rectangle
- procedure SetFloatRect (rc : TRect);
-
- // Gets the AppBar's docked dimensions
- function GetDockDims : TRect;
-
- // Sets the AppBar's docked dimensions
- procedure SetDockDims (rc : TRect);
-
- { Overridable functions }
-
- // Called when the AppBar's proposed state changes
- procedure OnAppBarStateChange (bProposed : Boolean;
- abEdgeProposed : TAppBarEdge); virtual;
-
- // Called if user attempts to dock an Autohide AppBar on
- // an edge that already contains an Autohide AppBar
- procedure OnAppBarForcedToDocked; virtual;
-
- // Called when AppBar gets an ABN_FULLSCREENAPP notification
- procedure OnABNFullScreenApp (bOpen : Boolean); virtual;
-
- // Called when AppBar gets an ABN_POSCHANGED notification
- procedure OnABNPosChanged; virtual;
-
- // Called when AppBar gets an ABN_WINDOWARRANGE notification
- procedure OnABNWindowArrange (bBeginning : Boolean); virtual;
-
- { Message handlers }
-
- // Called when the AppBar receives a WM_APPBARNOTIFY window message
- procedure OnAppBarCallbackMsg(var Msg : TMessage); message WM_APPBARNOTIFY;
-
- // Called when the AppBar form is first created
- procedure OnCreate (var Msg: TWMCreate); message WM_CREATE;
-
- // Called when the AppBar form is about to be destroyed
- procedure OnDestroy (var Msg : TWMDestroy); message WM_DESTROY;
-
- // Called when the AppBar receives a WM_WINDOWPOSCHANGED message
- procedure OnWindowPosChanged (var Msg : TWMWindowPosChanged);
- message WM_WINDOWPOSCHANGED;
-
- // Called when the AppBar receives a WM_ACTIVATE message
- procedure OnActivate (var Msg : TWMActivate); message WM_ACTIVATE;
-
- // Called every timer tick
- procedure OnAppBarTimer (Sender : TObject);
-
- // Called when the AppBar receives a WM_NCMOUSEMOVE message
- procedure OnNcMouseMove (var Msg : TWMNCMouseMove); message WM_NCMOUSEMOVE;
-
- // Called when the AppBar receives a WM_NCHITTEST message
- procedure OnNcHitTest (var Msg: TWMNCHitTest); message WM_NCHITTEST;
-
- // Called when the AppBar receives a WM_ENTERSIZEMOVE message
- procedure OnEnterSizeMove (var Msg : TMessage); message WM_ENTERSIZEMOVE;
-
- // Called when the AppBar receives a WM_EXITSIZEMOVE message
- procedure OnExitSizeMove (var Msg : TMessage); message WM_EXITSIZEMOVE;
-
- // Called when the AppBar receives a WM_MOVING message
- procedure OnMoving (var Msg : TMessage); message WM_MOVING;
-
- // Called when the AppBar receives a WM_SIZING message
- procedure OnSizing (var Msg : TMessage); message WM_SIZING;
-
- // Called when the AppBar receives a WM_GETMINMAXINFO message
- procedure OnGetMinMaxInfo (var Msg : TWMGetMinMaxInfo);
- message WM_GETMINMAXINFO;
-
- { AppBar-specific helper functions }
-
- // Returns TRUE if abEdge is ABE_LEFT or ABE_RIGHT, else FALSE is returned
- function IsEdgeLeftOrRight (abEdge : TAppBarEdge) : Boolean;
-
- // Returns TRUE if abEdge is ABE_TOP or ABE_BOTTOM, else FALSE is returned
- function IsEdgeTopOrBottom (abEdge : TAppBarEdge) : Boolean;
-
- // Returns TRUE if abEdge is ABE_FLOAT, else FALSE is returned
- function IsFloating (abEdge : TAppBarEdge) : Boolean;
-
- // Returns TRUE if abFlags contain an at least allowed edge to dock on
- function IsDockable (abFlags : TAppBarFlags) : Boolean;
-
- // Returns TRUE if abFlags contain abfAllowLeft and abfAllowRight
- function IsDockableVertically (abFlags : TAppBarFlags) : Boolean;
-
- // Returns TRUE if abFlags contain abfAllowTop and abfAllowBottom
- function IsDockableHorizontally (abFlags : TAppBarFlags) : Boolean;
-
- // Forces the shell to update its AppBar list and the workspace area
- procedure ResetSystemKnowledge;
-
- // Returns a proposed edge or ABE_FLOAT based on ABF_* flags and a
- // point specified in screen coordinates
- function GetEdgeFromPoint (abFlags : TAppBarFlags;
- pt : TSmallPoint) : TAppBarEdge;
-
- public
-
- { Public member functions }
-
- // Constructs an AppBar
- constructor Create (Owner : TComponent); override;
-
- // Destroys a previously created AppBar
- destructor Destroy; override;
-
- // Forces the AppBar's visual appearance to match its internal state
- procedure UpdateBar;
-
- published
-
- { Properties }
-
- // Allowed dockable edges
- property Flags : TAppBarFlags read FabFlags write FabFlags;
-
- // Horizontal size increment
- property HorzSizeInc : LongInt read FszSizeInc.cx write FszSizeInc.cx;
-
- // Vertical size increment
- property VertSizeInc : LongInt read FszSizeInc.cy write FszSizeInc.cy;
-
- // Edge to dock on
- property Edge : TAppBarEdge read GetEdge write SetEdge;
-
- // Auto-hide On/Off
- property AutoHide : Boolean read IsAutoHide write SetAutoHide;
-
- // Always On Top On/Off
- property AlwaysOnTop : Boolean read IsAlwaysOnTop write SetAlwaysOnTop;
-
- // Dimensions when docked on left, top, right and bottom
- property DockDims : TRect read GetDockDims write SetDockDims;
-
- // AppBar rectangle when floating
- property FloatRect : TRect read GetFloatRect write SetFloatRect;
-
- // AppBar MinMax dimensions when floating
- property MinWidth : LongInt read FABS.nMinWidth write FABS.nMinWidth;
- property MinHeight : LongInt read FABS.nMinHeight write FABS.nMinHeight;
- property MaxWidth : LongInt read FABS.nMaxWidth write FABS.nMaxWidth;
- property MaxHeight : LongInt read FABS.nMaxHeight write FABS.nMaxHeight;
-
- end;
-
- implementation
-
-
- { Internal implementation functions }
-
-
- // TAppBar.CreateParams ///////////////////////////////////////////////////////
- procedure TAppBar.CreateParams (var Params: TCreateParams);
- var
- dwAdd, dwRemove, dwAddEx, dwRemoveEx : DWORD;
- begin
- // Call the inherited first
- inherited CreateParams(Params);
-
- // Styles to be added
- dwAdd := 0;
- dwAddEx := WS_EX_TOOLWINDOW;
-
- // Styles to be removed
- dwRemove := WS_SYSMENU or WS_MAXIMIZEBOX or WS_MINIMIZEBOX;
- dwRemoveEx := WS_EX_APPWINDOW;
-
- // Modify style flags
- with Params do begin
- Style := Style and (not dwRemove);
- Style := Style or dwAdd;
- ExStyle := ExStyle and (not dwRemoveEx);
- ExStyle := ExStyle or dwAddEx;
- end;
- end;
-
-
- // TAppBar.AppBarMessage //////////////////////////////////////////////////////
- function TAppBar.AppBarMessage (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge;
- lParam : LPARAM;
- bRect : Boolean;
- var rc : TRect) : UINT;
- var
- abd : TAppBarData;
- begin
- // Initialize an APPBARDATA structure
- abd.cbSize := sizeof(abd);
- abd.hWnd := Handle;
- abd.uCallbackMessage := WM_APPBARNOTIFY;
- abd.uEdge := Ord(abEdge);
- if bRect then
- abd.rc := rc
- else
- abd.rc := Rect(0, 0, 0, 0);
- abd.lParam := lParam;
- Result := SHAppBarMessage(Ord(abMessage), abd);
-
- // If the caller passed a rectangle, return the updated rectangle
- if bRect then
- rc := abd.rc;
- end;
-
-
- // TAppBar.AppBarMessage1 /////////////////////////////////////////////////////
- function TAppBar.AppBarMessage1 (abMessage : TAppBarMessage) : UINT;
- var
- rc : TRect;
- begin
- Result := AppBarMessage(abMessage, abeFloat, 0, False, rc);
- end;
-
-
- // TAppBar.AppBarMessage2 /////////////////////////////////////////////////////
- function TAppBar.AppBarMessage2 (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge) : UINT;
- var
- rc : TRect;
- begin
- Result := AppBarMessage(abMessage, abEdge, 0, False, rc);
- end;
-
-
- // TAppBar.AppBarMessage3 /////////////////////////////////////////////////////
- function TAppBar.AppBarMessage3 (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge;
- lParam : LPARAM) : UINT;
- var
- rc : TRect;
- begin
- Result := AppBarMessage(abMessage, abEdge, lParam, False, rc);
- end;
-
-
- // TAppBar.AppBarMessage4 /////////////////////////////////////////////////////
- function TAppBar.AppBarMessage4 (abMessage : TAppBarMessage;
- abEdge : TAppBarEdge;
- lParam : LPARAM;
- var rc : TRect) : UINT;
- begin
- Result := AppBarMessage(abMessage, abEdge, lParam, True, rc);
- end;
-
-
- // TAppBar.CalcProposedState //////////////////////////////////////////////////
- function TAppBar.CalcProposedState (var pt : TSmallPoint) : TAppBarEdge;
- var
- bForceFloat : Boolean;
- begin
- // Force the AppBar to float if the user is holding down the Ctrl key
- // and the AppBar's style allows floating
- bForceFloat := ((GetKeyState(VK_CONTROL) and $8000) <> 0) and
- (abfAllowFloat in FabFlags);
- if bForceFloat then
- Result := abeFloat
- else
- Result := GetEdgeFromPoint(FabFlags, pt);
- end;
-
-
- // TAppBar.GetRect ////////////////////////////////////////////////////////////
- procedure TAppBar.GetRect (abEdgeProposed : TAppBarEdge;
- var rcProposed : TRect);
- begin
- // This function finds the x, y, cx, cy of the AppBar window
- if abEdgeProposed = abeFloat then begin
- // The AppBar is floating, the proposed rectangle is correct
- end else begin
- // The AppBar is docked or auto-hide
- // Set dimensions to full screen
- with rcProposed do begin
- Left := 0;
- Top := 0;
- Right := GetSystemMetrics(SM_CXSCREEN);
- Bottom := GetSystemMetrics(SM_CYSCREEN);
- end;
-
- // Subtract off what we want from the full screen dimensions
- if not IsAutohide then
- // Ask the shell where we can dock
- AppBarMessage4(abmQueryPos, abEdgeProposed, LPARAM(False), rcProposed);
-
- case abEdgeProposed of
- abeLeft:
- rcProposed.Right := rcProposed.Left + FABS.rcDockDims.Left;
- abeTop:
- rcProposed.Bottom := rcProposed.Top + FABS.rcDockDims.Top;
- abeRight:
- rcProposed.Left := rcProposed.Right - FABS.rcDockDims.Right;
- abeBottom:
- rcProposed.Top := rcProposed.Bottom - FABS.rcDockDims.Bottom;
- end; // end of case
-
- end; // end of else
- end;
-
-
- // TAppBar.AdjustLocationForAutohide //////////////////////////////////////////
- function TAppBar.AdjustLocationForAutohide (bShow : Boolean;
- var rc : TRect) : Boolean;
- var
- x, y : Integer;
- cxVisibleBorder, cyVisibleBorder : Integer;
- begin
- if ((GetEdge = abeUnknown) or (GetEdge = abeFloat) or
- (not IsAutohide)) then begin
- // If we are not docked on an edge OR we are not auto-hidden, there is
- // nothing for us to do; just return
- Result := False;
- Exit;
- end;
-
- // Showing/hiding doesn't change our size; only our position
- x := 0; y := 0; // Assume a position of (0, 0)
-
- if bShow then
- // If we are on the right or bottom, calculate our visible position
- case GetEdge of
- abeRight:
- x := GetSystemMetrics(SM_CXSCREEN) - (rc.Right - rc.Left);
- abeBottom:
- y := GetSystemMetrics(SM_CYSCREEN) - (rc.Bottom - rc.Top);
- end
- else begin
- // Keep a part of the AppBar visible at all times
- cxVisibleBorder := 2 * GetSystemMetrics(SM_CXBORDER);
- cyVisibleBorder := 2 * GetSystemMetrics(SM_CYBORDER);
-
- // Calculate our x or y coordinate so that only the border is visible
- case GetEdge of
- abeLeft:
- x := -((rc.Right - rc.Left) - cxVisibleBorder);
- abeRight:
- x := GetSystemMetrics(SM_CXSCREEN) - cxVisibleBorder;
- abeTop:
- y := -((rc.Bottom - rc.Top) - cyVisibleBorder);
- abeBottom:
- y := GetSystemMetrics(SM_CYSCREEN) - cyVisibleBorder;
- end;
- end;
-
- with rc do begin
- Right := x + (Right - Left);
- Bottom := y + (Bottom - Top);
- Left := x;
- Top := y;
- end;
-
- Result := True;
- end;
-
-
- // TAppBar.ShowHiddenAppBar ///////////////////////////////////////////////////
- procedure TAppBar.ShowHiddenAppBar (bShow : Boolean);
- var
- rc : TRect;
- begin
- // Get our window location in screen coordinates
- GetWindowRect(Handle, rc);
-
- // Assume that we are visible
- FbAutoHideIsVisible := True;
-
- if AdjustLocationForAutohide(bShow, rc) then begin
- // the rectangle was adjusted, we are an autohide bar
- // Rememebr whether we are visible or not
- FbAutoHideIsVisible := bShow;
-
- // Slide window in from or out to the edge
- SlideWindow(rc);
- end;
- end;
-
-
- // TAppBar.SlideWindow ////////////////////////////////////////////////////////
- procedure TAppBar.SlideWindow (var rcEnd : TRect);
- var
- bFullDragOn : Boolean;
- rcStart : TRect;
- dwTimeStart, dwTimeEnd, dwTime : DWORD;
- x, y, w, h : Integer;
- begin
- // Only slide the window if the user has FullDrag turned on
- SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, @bFullDragOn, 0);
-
- // Get the current window position
- GetWindowRect(Handle, rcStart);
- if (bFullDragOn and
- ((rcStart.Left <> rcEnd.Left ) or
- (rcStart.Top <> rcEnd.Top ) or
- (rcStart.Right <> rcEnd.Right ) or
- (rcStart.Bottom <> rcEnd.Bottom))) then begin
-
- // Get our starting and ending time
- dwTimeStart := GetTickCount;
- dwTimeEnd := dwTimeStart + AUTO_HIDE_TIMER_INTERVAL;
- dwTime := dwTimeStart;
- while (dwTime < dwTimeEnd) do begin
- // While we are still sliding, calculate our new position
- x := rcStart.Left - (rcStart.Left - rcEnd.Left)
- * Integer(dwTime - dwTimeStart) div AUTO_HIDE_TIMER_INTERVAL;
-
- y := rcStart.Top - (rcStart.Top - rcEnd.Top)
- * Integer(dwTime - dwTimeStart) div AUTO_HIDE_TIMER_INTERVAL;
-
- w := (rcStart.Right - rcStart.Left)
- - ((rcStart.Right - rcStart.Left) - (rcEnd.Right - rcEnd.Left))
- * Integer(dwTime - dwTimeStart) div AUTO_HIDE_TIMER_INTERVAL;
-
- h := (rcStart.Bottom - rcStart.Top)
- - ((rcStart.Bottom - rcStart.Top) - (rcEnd.Bottom - rcEnd.Top))
- * Integer(dwTime - dwTimeStart) div AUTO_HIDE_TIMER_INTERVAL;
-
- // Show the window at its changed position
- SetWindowPos(Handle, 0, x, y, w, h,
- SWP_NOZORDER or SWP_NOACTIVATE or SWP_DRAWFRAME);
- UpdateWindow(Handle);
- dwTime := GetTickCount;
- end;
- end;
-
- // Make sure that the window is at its final position
- Left := rcEnd.Left;
- Top := rcEnd.Top;
- Width := rcEnd.Right - rcEnd.Left;
- Height := rcEnd.Bottom - rcEnd.Top;
- end;
-
-
- // TAppBar.GetAutohideEdge ////////////////////////////////////////////////////
- function TAppBar.GetAutohideEdge : TAppBarEdge;
- begin
- if Handle = AppBarMessage2(abmGetAutoHideBar, abeLeft) then
- Result := abeLeft
- else if Handle = AppBarMessage2(abmGetAutoHideBar, abeTop) then
- Result := abeTop
- else if Handle = AppBarMessage2(abmGetAutoHideBar, abeRight) then
- Result := abeRight
- else if Handle = AppBarMessage2(abmGetAutoHideBar, abeBottom) then
- Result := abeBottom
- else
- // NOTE: If AppBar is docked but not auto-hidden, we return ABE_UNKNOWN
- Result := abeUnknown;
- end;
-
-
- // TAppBar.GetMessagePosition /////////////////////////////////////////////////
- function TAppBar.GetMessagePosition : TSmallPoint;
- var
- pt : TSmallPoint;
- dw : DWORD;
- begin
- dw := GetMessagePos;
- pt.X := SHORT(dw);
- pt.Y := SHORT((dw and $FFFF0000) shr 16);
- Result := pt;
- end;
-
-
- // TAppBar.ModifyStyle ////////////////////////////////////////////////////////
- function TAppBar.ModifyStyle (hWnd : THandle;
- nStyleOffset : Integer;
- dwRemove : DWORD;
- dwAdd : DWORD;
- nFlags : UINT) : Boolean;
- var
- dwStyle : DWORD;
- dwNewStyle : DWORD;
- begin
- dwStyle := GetWindowLong(hWnd, nStyleOffset);
- dwNewStyle := (dwStyle and (not dwRemove)) or dwAdd;
-
- if dwStyle = dwNewStyle then begin
- Result := False;
- Exit;
- end;
-
- SetWindowLong(hWnd, nStyleOffset, dwNewStyle);
-
- if nFlags <> 0 then
- SetWindowPos(hWnd, 0, 0, 0, 0, 0,
- SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or nFlags);
-
- Result := True;
- end;
-
-
- { Property selector functions }
-
-
- // TAppBar.GetEdge ////////////////////////////////////////////////////////////
- function TAppBar.GetEdge : TAppBarEdge;
- begin
- if FabEdgeProposedPrev <> abeUnknown then
- Result := FabEdgeProposedPrev
- else
- Result := FABS.abEdge;
- end;
-
-
- // TAppBar.SetEdge ////////////////////////////////////////////////////////////
- procedure TAppBar.SetEdge (abEdge : TAppBarEdge);
- var
- abCurrentEdge : TAppBarEdge;
- currentRect : TRect;
- rc : TRect;
- hWnd : THandle;
- begin
- // If the AppBar is registered as auto-hide, unregister it
- abCurrentEdge := GetAutohideEdge;
-
- if abCurrentEdge <> abeUnknown then
- // Our AppBar is auto-hidden, unregister it
- AppBarMessage3(abmSetAutoHideBar, abCurrentEdge, LPARAM(False));
-
- // Save the new requested state
- FABS.abEdge := abEdge;
-
- case abEdge of
-
- abeUnknown: begin
- // We are being completely unregistered.
- // Probably, the AppBar window is being destroyed.
- // If the AppBar is registered as NOT auto-hide, unregister it
- AppBarMessage1(abmRemove);
- end;
-
- abeFloat: begin
- // We are floating and therefore are just a regular window.
- // Tell the shell that the docked AppBar should be of 0x0 dimensions
- // so that the workspace is not affected by the AppBar
- currentRect := Rect(0, 0, 0, 0);
- AppBarMessage4(abmSetPos, abEdge, LPARAM(False), currentRect);
- Left := FABS.rcFloat.Left;
- Top := FABS.rcFloat.Top;
- Width := FABS.rcFloat.Right - FABS.rcFloat.Left;
- Height := FABS.rcFloat.Bottom - FABS.rcFloat.Top;
- end;
-
- else begin
- if IsAutohide and
- (AppBarMessage3(abmSetAutoHideBar,
- GetEdge,
- LPARAM(True)) = 0) then begin
- // We couldn't set the AppBar on a new edge, let's dock it instead
- FABS.bAutohide := False;
- // Call a virtual function to let derived classes know that the AppBar
- // changed from auto-hide to docked
- OnAppBarForcedToDocked;
- end;
-
- GetRect(GetEdge, rc);
- if IsAutohide then begin
- currentRect := Rect(0, 0, 0, 0);
- AppBarMessage4(abmSetPos, abeLeft, LPARAM(False), currentRect);
- end else begin
- // Tell the shell where the AppBar is
- AppBarMessage4(abmSetPos, abEdge, LPARAM(False), rc);
- end;
-
- AdjustLocationForAutohide(FbAutoHideIsVisible, rc);
-
- // Slide window in from or out to the edge
- SlideWindow(rc);
-
- end; // end of else
-
- end; // end of case
-
- // Set the AppBar's z-order appropriately
- hWnd := HWND_NOTOPMOST; // Assume normal Z-Order
- if FABS.bAlwaysOnTop then begin
- // If we are supposed to be always-on-top, put us there
- hWnd := HWND_TOPMOST;
- if FbFullScreenAppOpen then
- // But, if a full-screen window is opened, put ourself at the bottom
- // of the z-order so that we don't cover the full-screen window
- hWnd := HWND_BOTTOM;
- end;
- SetWindowPos(Handle,
- hWnd,
- 0, 0, 0, 0,
- SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
-
- // Make sure that any auto-hide appbars stay on top of us after we move
- // even though our activation state has not changed
- AppBarMessage1(abmActivate);
-
- // Tell our derived class that there is a state change
- OnAppBarStateChange(False, abEdge);
- end;
-
-
- // TAppBar.IsAutoHide /////////////////////////////////////////////////////////
- function TAppBar.IsAutoHide : Boolean;
- begin
- Result := FABS.bAutohide;
- end;
-
-
- // TAppBar.SetAutoHide ////////////////////////////////////////////////////////
- procedure TAppBar.SetAutoHide (bAutoHide : Boolean);
- begin
- FABS.bAutohide := bAutoHide;
- end;
-
-
- // TAppBar.IsAlwaysOnTop //////////////////////////////////////////////////////
- function TAppBar.IsAlwaysOnTop : Boolean;
- begin
- Result := FABS.bAlwaysOnTop;
- end;
-
-
- // TAppBar.SetAlwaysOnTop /////////////////////////////////////////////////////
- procedure TAppBar.SetAlwaysOnTop (bAlwaysOnTop : Boolean);
- begin
- FABS.bAlwaysOnTop := bAlwaysOnTop;
- end;
-
-
- // TAppBar.GetFloatRect ///////////////////////////////////////////////////////
- function TAppBar.GetFloatRect : TRect;
- begin
- Result := FABS.rcFloat;
- end;
-
-
- // TAppBar.SetFloatRect ///////////////////////////////////////////////////////
- procedure TAppBar.SetFloatRect (rc : TRect);
- begin
- FABS.rcFloat := rc;
- end;
-
-
- // TAppBar.GetDockDims ////////////////////////////////////////////////////////
- function TAppBar.GetDockDims : TRect;
- begin
- Result := FABS.rcDockDims;
- end;
-
-
- // TAppBar.SetDockDims ////////////////////////////////////////////////////////
- procedure TAppBar.SetDockDims (rc : TRect);
- begin
- FABS.rcDockDims := rc;
- end;
-
-
- { Overridable functions }
-
-
- // TAppBar.OnAppBarStateChange ////////////////////////////////////////////////
- procedure TAppBar.OnAppBarStateChange (bProposed : Boolean;
- abEdgeProposed : TAppBarEdge);
- begin
- // Hide the window adorments when docked
- if abEdgeProposed = abeFloat then
- ModifyStyle(Handle, GWL_STYLE, 0, WS_CAPTION or WS_SYSMENU, SWP_DRAWFRAME)
- else
- ModifyStyle(Handle, GWL_STYLE, WS_CAPTION or WS_SYSMENU, 0, SWP_DRAWFRAME);
- end;
-
-
- // TAppBar.OnAppBarForcedToDocked /////////////////////////////////////////////
- procedure TAppBar.OnAppBarForcedToDocked;
- const
- CRLF = #10#13;
- begin
- // Display the application name as the message box caption text.
- MessageDlg('There is already an auto hidden window on this edge.' + CRLF +
- 'Only one auto hidden window is allowed on each edge.',
- mtInformation,
- [mbOk],
- 0);
- end;
-
- // TAppBar.OnABNFullScreenApp /////////////////////////////////////////////////
- procedure TAppBar.OnABNFullScreenApp (bOpen : Boolean);
- begin
- // This function is called when a FullScreen window is openning or
- // closing. A FullScreen window is a top-level window that has its caption
- // above the top of the screen allowing the entire screen to be occupied
- // by the window's client area.
-
- // If the AppBar is a topmost window when a FullScreen window is activated,
- // we need to change our window to a non-topmost window so that the AppBar
- // doesn't cover the FullScreen window's client area.
-
- // If the FullScreen window is closing, we need to set the AppBar's
- // Z-Order back to when the user wants it to be.
- FbFullScreenAppOpen := bOpen;
- UpdateBar;
- end;
-
-
- // TAppBar.OnABNPosChanged ////////////////////////////////////////////////////
- procedure TAppBar.OnABNPosChanged;
- begin
- // The TaskBar or another AppBar has changed its size or position
- if (GetEdge <> abeFloat) and (not IsAutohide) then
- // If we're not floating and we're not auto-hidden, we have to
- // reposition our window
- UpdateBar;
- end;
-
-
- // TAppBar.OnABNWindowArrange /////////////////////////////////////////////////
- procedure TAppBar.OnABNWindowArrange (bBeginning : Boolean);
- begin
- // This function intentionally left blank
- end;
-
-
- { Message handlers }
-
-
- // TAppBar.OnAppBarCallbackMsg ////////////////////////////////////////////////
- procedure TAppBar.OnAppBarCallbackMsg (var Msg : TMessage);
- begin
- case Msg.WParam of
-
- ABN_FULLSCREENAPP:
- OnABNFullScreenApp(Msg.LParam <> 0);
-
- ABN_POSCHANGED:
- OnABNPosChanged;
-
- ABN_WINDOWARRANGE:
- OnABNWindowArrange(Msg.LParam <> 0);
- end;
- end;
-
-
- // TAppBar.OnCreate ///////////////////////////////////////////////////////////
- procedure TAppBar.OnCreate (var Msg : TWMCreate);
- begin
- inherited;
- // Associate a timer with the AppBar. The timer is used to determine
- // when a visible, inactive, auto-hide AppBar should be re-hidden
- FTimer := TTimer.Create(Self);
- with FTimer do begin
- Interval := AUTO_HIDE_TIMER_INTERVAL;
- OnTimer := OnAppBarTimer;
- Enabled := True;
- end;
-
- // Save the initial position of the floating AppBar
- FABS.rcFloat.Left := Left;
- FABS.rcFloat.Top := Top;
-
- // Register our AppBar window with the Shell
- AppBarMessage1(abmNew);
-
- // Update AppBar internal state
- UpdateBar;
-
- // Save the initial size of the floating AppBar
- PostMessage(Handle, WM_ENTERSIZEMOVE, 0, 0);
- PostMessage(Handle, WM_EXITSIZEMOVE, 0, 0);
- end;
-
-
- // TAppBar.OnDestroy //////////////////////////////////////////////////////////
- procedure TAppBar.OnDestroy (var Msg : TWMDestroy);
- begin
- // Free the Autohide timer
- FTimer.Enabled := False;
- FTimer.Free;
- // Unregister our AppBar window with the Shell
- SetEdge(abeUnknown);
- inherited;
- end;
-
-
- // TAppBar.OnWindowPosChanged /////////////////////////////////////////////////
- procedure TAppBar.OnWindowPosChanged (var Msg : TWMWindowPosChanged);
- begin
- inherited;
- // When our window changes position, tell the Shell so that any
- // auto-hidden AppBar on our edge stays on top of our window making it
- // always accessible to the user
- AppBarMessage1(abmWindowPosChanged);
- end;
-
-
- // TAppBar.OnActivate /////////////////////////////////////////////////////////
- procedure TAppBar.OnActivate (var Msg : TWMActivate);
- begin
- inherited;
- if Msg.Active = WA_INACTIVE then
- // Hide the AppBar if we are docked and auto-hidden
- ShowHiddenAppBar(False);
- // When our window changes position, tell the Shell so that any
- // auto-hidden AppBar on our edge stays on top of our window making it
- // always accessible to the user.
- AppBarMessage1(abmActivate);
- end;
-
-
- // TAppBar.OnAppBarTimer //////////////////////////////////////////////////////
- procedure TAppBar.OnAppBarTimer (Sender : TObject);
- var
- pt : TSmallPoint;
- rc : TRect;
- begin
- if GetActiveWindow <> Handle then begin
- // Possibly hide the AppBar if we are not the active window
- // Get the position of the mouse and the AppBar's position
- // Everything must be in screen coordinates
- pt := GetMessagePosition;
- GetWindowRect(Handle, rc);
- // Add a little margin around the AppBar
- InflateRect(rc,
- 2 * GetSystemMetrics(SM_CXDOUBLECLK),
- 2 * GetSystemMetrics(SM_CYDOUBLECLK));
- if not PtInRect(rc, SmallPointToPoint(pt)) then
- // If the mouse is NOT over the AppBar, hide the AppBar
- ShowHiddenAppBar(False);
- end;
- inherited;
- end;
-
-
- // TAppBar.OnNcMouseMove //////////////////////////////////////////////////////
- procedure TAppBar.OnNcMouseMove (var Msg : TWMNCMouseMove);
- begin
- // If we are a docked, auto-hidden AppBar, shown us
- // when the user moves over our non-client area
- ShowHiddenAppBar(True);
- inherited;
- end;
-
-
- // TAppBar.OnNcHitTest ////////////////////////////////////////////////////////
- procedure TAppBar.OnNcHitTest (var Msg: TWMNCHitTest);
- var
- u : UINT;
- bPrimaryMouseBtnDown : Boolean;
- rcClient : TRect;
- pt : TPoint;
- vKey : Integer;
- begin
- // Find out what the system thinks is the hit test code
- inherited;
- u := Msg.Result;
-
- // NOTE: If the user presses the secondary mouse button, pretend that the
- // user clicked on the client area so that we get WM_CONTEXTMENU messages
- if GetSystemMetrics(SM_SWAPBUTTON) <> 0 then
- vKey := VK_RBUTTON
- else
- vKey := VK_LBUTTON;
- bPrimaryMouseBtnDown := ((GetAsyncKeyState(vKey) and $8000) <> 0);
-
- if (u = HTCLIENT) and bPrimaryMouseBtnDown then
- // User clicked in client area, allow AppBar to move. We get this
- // behavior by pretending that the user clicked on the caption area
- u := HTCAPTION;
-
- // If the AppBar is floating and the hittest code is a resize code...
- if ((GetEdge = abeFloat) and
- (HTSIZEFIRST <= u) and (u <= HTSIZELAST)) then begin
- case u of
- HTLEFT, HTRIGHT:
- if FszSizeInc.cx = 0
- then u := HTBORDER;
- HTTOP, HTBOTTOM:
- if FszSizeInc.cy = 0
- then u := HTBORDER;
- HTTOPLEFT:
- if (FszSizeInc.cx = 0) and (FszSizeInc.cy = 0)
- then u := HTBORDER
- else if (FszSizeInc.cx = 0) and (FszSizeInc.cy <> 0)
- then u := HTTOP
- else if (FszSizeInc.cx <> 0) and (FszSizeInc.cy = 0)
- then u := HTLEFT;
- HTTOPRIGHT:
- if (FszSizeInc.cx = 0) and (FszSizeInc.cy = 0)
- then u := HTBORDER
- else if (FszSizeInc.cx = 0) and (FszSizeInc.cy <> 0)
- then u := HTTOP
- else if (FszSizeInc.cx <> 0) and (FszSizeInc.cy = 0)
- then u := HTRIGHT;
- HTBOTTOMLEFT:
- if (FszSizeInc.cx = 0) and (FszSizeInc.cy = 0)
- then u := HTBORDER
- else if (FszSizeInc.cx = 0) and (FszSizeInc.cy <> 0)
- then u := HTBOTTOM
- else if (FszSizeInc.cx <> 0) and (FszSizeInc.cy = 0)
- then u := HTLEFT;
- HTBOTTOMRIGHT:
- if (FszSizeInc.cx = 0) and (FszSizeInc.cy = 0)
- then u := HTBORDER
- else if (FszSizeInc.cx = 0) and (FszSizeInc.cy <> 0)
- then u := HTBOTTOM
- else if (FszSizeInc.cx <> 0) and (FszSizeInc.cy = 0)
- then u := HTRIGHT;
- end;
- end;
-
- // When the AppBar is docked, the user can resize only one edge.
- // This next section determines which edge the user can resize.
- // To allow resizing, the AppBar window must have the WS_THICKFRAME style
-
- // If the AppBar is docked and the hittest code is a resize code...
- if ((GetEdge <> abeFloat) and (GetEdge <> abeUnknown) and
- (HTSIZEFIRST <= u) and (u <= HTSIZELAST)) then begin
-
- if (IsEdgeLeftOrRight(GetEdge) and (FszSizeInc.cx = 0)) or
- (not IsEdgeLeftOrRight(GetEdge) and (FszSizeInc.cy = 0)) then begin
- // If the width/height size increment is zero, then resizing is NOT
- // allowed for the edge that the AppBar is docked on
- u := HTBORDER; // Pretend that the mouse is not on a resize border
- end else begin
- // Resizing IS allowed for the edge that the AppBar is docked on
- // Get the location of the appbar's client area in screen coordinates
- rcClient := GetClientRect;
- pt.X := rcClient.Left;
- pt.Y := rcClient.Top;
- pt := ClientToScreen(pt);
- rcClient.Left := pt.X;
- rcClient.Top := pt.Y;
- pt.X := rcClient.Right;
- pt.Y := rcClient.Bottom;
- pt := ClientToScreen(pt);
- rcClient.Right := pt.X;
- rcClient.Bottom := pt.Y;
-
- u := HTBORDER; // Assume that we can't resize
- case GetEdge of
- abeLeft:
- if Msg.XPos > rcClient.Right then
- u := HTRIGHT;
- abeTop:
- if Msg.YPos > rcClient.Bottom then
- u := HTBOTTOM;
- abeRight:
- if Msg.XPos < rcClient.Left then
- u := HTLEFT;
- abeBottom:
- if Msg.YPos < rcClient.Top then
- u := HTTOP;
- end; // end of case
- end; // end of else
- end;
-
- // Return the hittest code
- Msg.Result := u;
- end;
-
-
- // TAppBar.OnEnterSizeMove ////////////////////////////////////////////////////
- procedure TAppBar.OnEnterSizeMove (var Msg : TMessage);
- begin
- // The user started moving/resizing the AppBar, save its current state
- FabEdgeProposedPrev := GetEdge;
- end;
-
-
- // TAppBar.OnExitSizeMove /////////////////////////////////////////////////////
- procedure TAppBar.OnExitSizeMove (var Msg : TMessage);
- var
- abEdgeProposedPrev : TAppBarEdge;
- rc : TRect;
- begin
- // The user stopped moving/resizing the AppBar, set the new state
- // Save the new proposed state of the AppBar
- abEdgeProposedPrev := FabEdgeProposedPrev;
-
- // Set the proposed state back to unknown. This causes GetState
- // to return the current state rather than the proposed state
- FabEdgeProposedPrev := abeUnknown;
-
- // Get the location of the window in screen coordinates
- GetWindowRect(Handle, rc);
-
- // If the AppBar's state has changed...
- if GetEdge = abEdgeProposedPrev then
- case GetEdge of
- abeLeft:
- // Save the new width of the docked AppBar
- FABS.rcDockDims.Left := rc.Right - rc.Left;
- abeTop:
- // Save the new height of the docked AppBar
- FABS.rcDockDims.Top := rc.Bottom - rc.Top;
- abeRight:
- // Save the new width of the docked AppBar
- FABS.rcDockDims.Right := rc.Right - rc.Left;
- abeBottom:
- // Save the new height of the docked AppBar
- FABS.rcDockDims.Bottom := rc.Bottom - rc.Top;
- end;
-
- // Always save the new position of the floating AppBar
- if abEdgeProposedPrev = abeFloat then
- FABS.rcFloat := rc;
-
- // After setting the dimensions, set the AppBar to the proposed state
- SetEdge(abEdgeProposedPrev);
- end;
-
-
- // TAppBar.OnMoving ///////////////////////////////////////////////////////////
- procedure TAppBar.OnMoving (var Msg : TMessage);
- var
- prc : PRect;
- pt : TSmallPoint;
- abEdgeProposed : TAppBarEdge;
- w, h : Integer;
- begin
- // We control the moving of the AppBar. For example, if the mouse moves
- // close to an edge, we want to dock the AppBar
- // The lParam contains the window's position proposed by the system
- prc := PRect(Msg.LParam);
-
- // Get the location of the mouse cursor
- pt := GetMessagePosition;
-
- // Where should the AppBar be based on the mouse position?
- abEdgeProposed := CalcProposedState(pt);
-
- if ((FabEdgeProposedPrev <> abeFloat) and
- (abEdgeProposed = abeFloat)) then begin
- // While moving, the user took us from a docked/autohidden state to
- // the float state. We have to calculate a rectangle location so that
- // the mouse cursor stays inside the window.
- prc^ := GetFloatRect;
- w := prc^.Right - prc^.Left;
- h := prc^.Bottom - prc^.Top;
- with prc^ do begin
- Left := pt.X - w div 2;
- Top := pt.Y;
- Right := pt.X - w div 2 + w;
- Bottom := pt.Y + h;
- end;
- end;
-
- // Remember the most-recently proposed state
- FabEdgeProposedPrev := abEdgeProposed;
-
- // Tell the system where to move the window based on the proposed state
- GetRect(abEdgeProposed, prc^);
-
- // Tell our derived class that there is a proposed state change
- OnAppBarStateChange(True, abEdgeProposed);
- end;
-
-
- // TAppBar.OnSizing ///////////////////////////////////////////////////////////
- procedure TAppBar.OnSizing (var Msg : TMessage);
- var
- prc : PRect;
- rcBorder : TRect;
- nWidthNew, nHeightNew : Integer;
- begin
- // We control the sizing of the AppBar. For example, if the user re-sizes
- // an edge, we want to change the size in descrete increments.
- // The lParam contains the window's position proposed by the system
- prc := PRect(Msg.LParam);
-
- // Get the minimum size of the window assuming it has no client area.
- // This is the width/height of the window that must always be present
- rcBorder := Rect(0, 0, 0, 0);
- AdjustWindowRectEx(rcBorder,
- GetWindowLong(Handle, GWL_STYLE),
- False,
- GetWindowLong(Handle, GWL_EXSTYLE));
-
- // We force the window to resize in discrete units set by the FszSizeInc
- // member. From the new, proposed window dimensions passed to us, round
- // the width/height to the nearest discrete unit
- if FszSizeInc.cx <> 0 then
- nWidthNew := ((prc^.Right - prc^.Left) - (rcBorder.Right - rcBorder.Left)
- + FszSizeInc.cx div 2) div FszSizeInc.cx * FszSizeInc.cx
- + (rcBorder.Right - rcBorder.Left)
- else
- nWidthNew := prc^.Right - prc^.Left;
-
- if FszSizeInc.cy <> 0 then
- nHeightNew := ((prc^.Bottom - prc^.Top) - (rcBorder.Bottom - rcBorder.Top)
- + FszSizeInc.cy div 2) div FszSizeInc.cy * FszSizeInc.cy
- + (rcBorder.Bottom - rcBorder.Top)
- else
- nHeightNew := prc^.Bottom - prc^.Top;
-
- // Adjust the rectangle's dimensions
- case Msg.wParam of
- WMSZ_LEFT:
- prc^.Left := prc^.Right - nWidthNew;
-
- WMSZ_TOP:
- prc^.Top := prc^.Bottom - nHeightNew;
-
- WMSZ_RIGHT:
- prc^.Right := prc^.Left + nWidthNew;
-
- WMSZ_BOTTOM:
- prc^.Bottom := prc^.Top + nHeightNew;
-
- WMSZ_BOTTOMLEFT: begin
- prc^.Bottom := prc^.Top + nHeightNew;
- prc^.Left := prc^.Right - nWidthNew;
- end;
-
- WMSZ_BOTTOMRIGHT: begin
- prc^.Bottom := prc^.Top + nHeightNew;
- prc^.Right := prc^.Left + nWidthNew;
- end;
-
- WMSZ_TOPLEFT: begin
- prc^.Left := prc^.Right - nWidthNew;
- prc^.Top := prc^.Bottom - nHeightNew;
- end;
-
- WMSZ_TOPRIGHT: begin
- prc^.Top := prc^.Bottom - nHeightNew;
- prc^.Right := prc^.Left + nWidthNew;
- end;
- end; // end of case
- end;
-
-
- // TAppBar.OnGetMinMaxInfo ////////////////////////////////////////////////////
- procedure TAppBar.OnGetMinMaxInfo (var Msg : TWMGetMinMaxInfo);
- begin
- if GetEdge = abeFloat then
- with Msg.MinMaxInfo^ do begin
- ptMinTrackSize.X := FABS.nMinWidth;
- ptMinTrackSize.Y := FABS.nMinHeight;
- ptMaxTrackSize.X := FABS.nMaxWidth;
- ptMaxTrackSize.Y := FABS.nMaxHeight;
- end
- else
- with Msg.MinMaxInfo^ do begin
- ptMinTrackSize.X := 0;
- ptMinTrackSize.Y := 0;
- ptMaxTrackSize.X := GetSystemMetrics(SM_CXSCREEN);
- ptMaxTrackSize.Y := GetSystemMetrics(SM_CYSCREEN);
- if not IsEdgeTopOrBottom(GetEdge) then
- ptMaxTrackSize.X := ptMaxTrackSize.X div 2;
- if not IsEdgeLeftOrRight(GetEdge) then
- ptMaxTrackSize.Y := ptMaxTrackSize.Y div 2;
- end;
- end;
-
-
- { AppBar-specific helper functions }
-
-
- // TAppBar.IsEdgeLeftOrRight //////////////////////////////////////////////////
- function TAppBar.IsEdgeLeftOrRight (abEdge : TAppBarEdge) : Boolean;
- begin
- Result := (abEdge in [abeLeft, abeRight]);
- end;
-
-
- // TAppBar.IsEdgeTopOrBottom //////////////////////////////////////////////////
- function TAppBar.IsEdgeTopOrBottom (abEdge : TAppBarEdge) : Boolean;
- begin
- Result := (abEdge in [abeTop, abeBottom]);
- end;
-
-
- // TAppBar.IsFloating /////////////////////////////////////////////////////////
- function TAppBar.IsFloating (abEdge : TAppBarEdge) : Boolean;
- begin
- Result := (abEdge = abeFloat);
- end;
-
-
- // TAppBar.IsDockable /////////////////////////////////////////////////////////
- function TAppBar.IsDockable (abFlags : TAppBarFlags) : Boolean;
- begin
- Result := ((abFlags * [abfAllowLeft .. abfAllowBottom]) <> []);
- end;
-
-
- // TAppBar.IsDockableVertically ///////////////////////////////////////////////
- function TAppBar.IsDockableVertically (abFlags : TAppBarFlags) : Boolean;
- begin
- Result := ((abFlags * [abfAllowLeft, abfAllowRight]) <> []);
- end;
-
-
- // TAppBar.IsDockableHorizontally /////////////////////////////////////////////
- function TAppBar.IsDockableHorizontally (abFlags : TAppBarFlags) : Boolean;
- begin
- Result := ((abFlags * [abfAllowTop, abfAllowBottom]) <> []);
- end;
-
-
- // TAppBar.ResetSystemKnowledge ///////////////////////////////////////////////
- procedure TAppBar.ResetSystemKnowledge;
- {$ifdef DEBUG}
- var
- abd : TAppBarData;
- begin
- abd.cbSize := sizeof(abd);
- abd.hWnd := 0;
- SHAppBarMessage(ABM_REMOVE, abd);
- end;
- {$else}
- begin
- // nothing to do when not in debug mode
- end;
- {$endif}
-
-
- // TAppBar.GetEdgeFromPoint ///////////////////////////////////////////////////
- function TAppBar.GetEdgeFromPoint (abFlags : TAppBarFlags;
- pt : TSmallPoint) : TAppBarEdge;
- var
- rc : TRect;
- cxScreen : Integer;
- cyScreen : Integer;
- ptCenter : TSmallPoint;
- ptOffset : TSmallPoint;
- bIsLeftOrRight : Boolean;
- abSubstEdge : TAppBarEdge;
- begin
- // Let's get floating out of the way first
- if abfAllowFloat in abFlags then begin
-
- // Get the rectangle that bounds the size of the screen
- // minus any docked (but not-autohidden) AppBars
- SystemParametersInfo(SPI_GETWORKAREA, 0, @rc, 0);
-
- // Leave a 1/2 width/height-of-a-scrollbar gutter around the workarea
- InflateRect(rc,
- -GetSystemMetrics(SM_CXVSCROLL),
- -GetSystemMetrics(SM_CYHSCROLL));
-
- // If the point is in the adjusted workarea OR no edges are allowed
- if PtInRect(rc, SmallPointToPoint(pt)) or
- not IsDockable(abFlags) then begin
- // The AppBar should float
- Result := abeFloat;
- Exit;
- end;
- end;
-
- // If we get here, the AppBar should be docked; determine the proper edge
- // Get the dimensions of the screen
- cxScreen := GetSystemMetrics(SM_CXSCREEN);
- cyScreen := GetSystemMetrics(SM_CYSCREEN);
-
- // Find the center of the screen
- ptCenter.X := cxScreen div 2;
- ptCenter.Y := cyScreen div 2;
-
- // Find the distance from the point to the center
- ptOffset.X := pt.X - ptCenter.X;
- ptOffset.Y := pt.Y - ptCenter.Y;
-
- // Determine if the point is farther from the left/right or top/bottom
- bIsLeftOrRight :=
- ((Abs(ptOffset.Y) * cxScreen) <= (Abs(ptOffset.X) * cyScreen));
-
- // Propose an edge
- if bIsLeftOrRight then begin
- if 0 <= ptOffset.X then
- Result := abeRight
- else
- Result := abeLeft;
- end else begin
- if 0 <= ptOffset.Y then
- Result := abeBottom
- else
- Result := abeTop;
- end;
-
- // Calculate an edge substitute
- if abfAllowFloat in abFlags then
- abSubstEdge := abeFloat
- else
- abSubstEdge := FABS.abEdge;
-
- // Check if the proposed edge is allowed. If not, return the edge substitute
- case Result of
- abeLeft : if not (abfAllowLeft in abFlags) then Result := abSubstEdge;
- abeTop : if not (abfAllowTop in abFlags) then Result := abSubstEdge;
- abeRight : if not (abfAllowRight in abFlags) then Result := abSubstEdge;
- abeBottom: if not (abfAllowBottom in abFlags) then Result := abSubstEdge;
- end;
-
- end;
-
-
- { Public member functions }
-
-
- // TAppBar.Create /////////////////////////////////////////////////////////////
- constructor TAppBar.Create (Owner : TComponent);
- begin
- // Force the shell to update its list of AppBars and the workarea.
- // This is a precaution and is very useful when debugging. If you create
- // an AppBar and then just terminate the application, the shell still
- // thinks that the AppBar exists and the user's workarea is smaller than
- // it should be. When a new AppBar is created, calling this function
- // fixes the user's workarea.
- ResetSystemKnowledge;
-
- // Set default state of AppBar to float with no width & height
- FABS.cbSize := sizeof(TAppBarSettings);
- FABS.abEdge := abeFloat;
- FABS.bAutohide := False;
- FABS.bAlwaysOnTop := True;
- FABS.rcDockDims.Left := AB_DEF_DOCK_DIM;
- FABS.rcDockDims.Top := AB_DEF_DOCK_DIM;
- FABS.rcDockDims.Right := AB_DEF_DOCK_DIM;
- FABS.rcDockDims.Bottom := AB_DEF_DOCK_DIM;
- FABS.rcFloat.Left := 0;
- FABS.rcFloat.Top := 0;
- FABS.rcFloat.Right := 0;
- FABS.rcFloat.Bottom := 0;
- FABS.nMinWidth := 0;
- FABS.nMinHeight := 0;
- FABS.nMaxWidth := GetSystemMetrics(SM_CXSCREEN);
- FABS.nMaxHeight := GetSystemMetrics(SM_CYSCREEN);
- FabFlags := [abfAllowLeft .. abfAllowFloat];
- FszSizeInc.cx := AB_DEF_SIZE_INC;
- FszSizeInc.cy := AB_DEF_SIZE_INC;
- FabEdgeProposedPrev := abeUnknown;
- FbFullScreenAppOpen := False;
- FbAutoHideIsVisible := False;
-
- // Call base class
- inherited Create(Owner);
- end;
-
-
- // TAppBar.Destroy ////////////////////////////////////////////////////////////
- destructor TAppBar.Destroy;
- begin
- ResetSystemKnowledge;
-
- // Call base class
- inherited Destroy;
- end;
-
-
- // TAppBar.UpdateBar //////////////////////////////////////////////////////////
- procedure TAppBar.UpdateBar;
- begin
- SetEdge(GetEdge);
- end;
-
- end.
-